/*
 * @(#)MethodWriterImpl.java 1.64 04/04/20
 * 
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. SUN
 * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package net.sf.odinms.exttools.doclet.writers;

import java.io.IOException;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.Type;
import com.sun.tools.doclets.internal.toolkit.MemberSummaryWriter;
import com.sun.tools.doclets.internal.toolkit.MethodWriter;
import com.sun.tools.doclets.internal.toolkit.taglets.DeprecatedTaglet;
import com.sun.tools.doclets.internal.toolkit.util.ImplementedMethods;
import com.sun.tools.doclets.internal.toolkit.util.Util;
import com.sun.tools.doclets.internal.toolkit.util.VisibleMemberMap;
import net.sf.odinms.exttools.doclet.Config;

/**
 * Writes method documentation in HTML format.
 * 
 * @author Robert Field
 * @author Atul M Dambalkar
 * @author Jamie Ho (rewrite)
 * 
 * @deprecated Legacy code from Standard Doclet.
 */
public class MethodWriterImpl extends AbstractExecutableMemberWriter implements
		MethodWriter, MemberSummaryWriter {
	
	/**
	 * Construct a new MethodWriterImpl.
	 * 
	 * @param writer the writer for the class that the methods belong to.
	 * @param classDoc the class being documented.
	 */
	public MethodWriterImpl(SubWriterHolderWriter writer, ClassDoc classDoc) {
		super(writer, classDoc);
	}
	
	/**
	 * Construct a new MethodWriterImpl.
	 * 
	 * @param writer The writer for the class that the methods belong to.
	 */
	public MethodWriterImpl(SubWriterHolderWriter writer) {
		super(writer);
	}
	
	/**
	 * Write the methods summary header for the given class.
	 * 
	 * @param classDoc the class the summary belongs to.
	 */
	public void writeMemberSummaryHeader(ClassDoc classDoc) {
		printedSummaryHeader = true;
		writer.println();
		writer.println("<!-- ========== METHOD SUMMARY =========== -->");
		writer.println();
		writer.printSummaryHeader(this, classDoc);
	}
	
	/**
	 * Write the methods summary footer for the given class.
	 * 
	 * @param classDoc the class the summary belongs to.
	 */
	public void writeMemberSummaryFooter(ClassDoc classDoc) {
		writer.printSummaryFooter(this, classDoc);
	}
	
	/**
	 * Write the inherited methods summary header for the given class.
	 * 
	 * @param classDoc the class the summary belongs to.
	 */
	public void writeInheritedMemberSummaryHeader(ClassDoc classDoc) {
		if (!printedSummaryHeader) {
			// We don't want inherited summary to not be under heading.
			writeMemberSummaryHeader(classDoc);
			writeMemberSummaryFooter(classDoc);
			printedSummaryHeader = true;
		}
		writer.printInheritedSummaryHeader(this, classDoc);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void writeInheritedMemberSummary(ClassDoc classDoc,
			ProgramElementDoc method, boolean isFirst, boolean isLast) {
		writer.printInheritedSummaryMember(this, classDoc, method, isFirst);
	}
	
	/**
	 * Write the inherited methods summary footer for the given class.
	 * 
	 * @param classDoc the class the summary belongs to.
	 */
	public void writeInheritedMemberSummaryFooter(ClassDoc classDoc) {
		writer.printInheritedSummaryFooter(this, classDoc);
		;
	}
	
	/**
	 * Write the header for the method documentation.
	 * 
	 * @param classDoc the class that the methods belong to.
	 */
	public void writeHeader(ClassDoc classDoc, String header) {
		writer.println();
		writer.println("<!-- ============ METHOD DETAIL ========== -->");
		writer.println();
		writer.anchor("method_detail");
		writer.printTableHeadingBackground(header);
	}
	
	/**
	 * Write the method header for the given method.
	 * 
	 * @param method the method being documented.
	 * @param isFirst the flag to indicate whether or not the method is the
	 *        first to be documented.
	 */
	public void writeMethodHeader(MethodDoc method, boolean isFirst) {
		if (!isFirst) {
			writer.printMemberHeader();
		}
		writer.println();
		String erasureAnchor;
		if ((erasureAnchor = getErasureAnchor(method)) != null) {
			writer.anchor(erasureAnchor);
		}
		writer.anchor(method);
		writer.h3();
		writer.print(method.name());
		writer.h3End();
	}
	
	/**
	 * Write the signature for the given method.
	 * 
	 * @param method the method being documented.
	 */
	public void writeSignature(MethodDoc method) {
		writer.displayLength = 0;
		writer.pre();
		writer.writeAnnotationInfo(method);
		printModifiers(method);
		writeTypeParameters(method);
		printReturnType(method);
		if (configuration().linksource) {
			writer.printSrcLink(method, method.name());
		} else {
			bold(method.name());
		}
		writeParameters(method);
		writeExceptions(method);
		writer.preEnd();
		writer.dl();
	}
	
	/**
	 * Write the deprecated output for the given method.
	 * 
	 * @param method the method being documented.
	 */
	public void writeDeprecated(MethodDoc method) {
		String output = ((TagletOutputImpl) (new DeprecatedTaglet()).getTagletOutput(
				method, writer.getTagletWriterInstance(false))).toString();
		if (output != null && output.trim().length() > 0) {
			writer.print(output);
		}
	}
	
	/**
	 * Write the comments for the given method.
	 * 
	 * @param method the method being documented.
	 */
	public void writeComments(Type holder, MethodDoc method) {
		ClassDoc holderClassDoc = holder.asClassDoc();
		if (method.inlineTags().length > 0) {
			if (holder.asClassDoc().equals(classdoc)
					|| (!(holderClassDoc.isPublic() || Util.isLinkable(
							holderClassDoc, configuration())))) {
				writer.dd();
				writer.printInlineComment(method);
			} else {
				String classlink = writer.codeText(writer.getDocLink(
						LinkInfoImpl.CONTEXT_METHOD_DOC_COPY,
						holder.asClassDoc(), method,
						holder.asClassDoc().isIncluded()
								? holder.typeName()
								: holder.qualifiedTypeName(), false));
				writer.dd();
				writer.boldText(holder.asClassDoc().isClass()
						? "doclet.Description_From_Class"
						: "doclet.Description_From_Interface", classlink);
				writer.ddEnd();
				writer.dd();
				writer.printInlineComment(method);
			}
		}
	}
	
	/**
	 * Write the tag output for the given method.
	 * 
	 * @param method the method being documented.
	 */
	public void writeTags(MethodDoc method) {
		writer.printTags(method);
	}
	
	/**
	 * Write the method footer.
	 */
	public void writeMethodFooter() {
		writer.ddEnd();
		writer.dlEnd();
	}
	
	/**
	 * Write the footer for the method documentation.
	 * 
	 * @param classDoc the class that the methods belong to.
	 */
	public void writeFooter(ClassDoc classDoc) {
		// No footer to write for method documentation
	}
	
	/**
	 * Close the writer.
	 */
	public void close() throws IOException {
		writer.close();
	}
	
	public int getMemberKind() {
		return VisibleMemberMap.METHODS;
	}
	
	public void printSummaryLabel(ClassDoc cd) {
		writer.boldText("doclet.Method_Summary");
	}
	
	public void printSummaryAnchor(ClassDoc cd) {
		writer.anchor("method_summary");
	}
	
	public void printInheritedSummaryAnchor(ClassDoc cd) {
		writer.anchor("methods_inherited_from_class_"
				+ Config.getInstance().getClassName(cd));
	}
	
	public void printInheritedSummaryLabel(ClassDoc cd) {
		String classlink = writer.getPreQualifiedClassLink(
				LinkInfoImpl.CONTEXT_MEMBER, cd, false);
		writer.bold();
		String key = cd.isClass()
				? "doclet.Methods_Inherited_From_Class"
				: "doclet.Methods_Inherited_From_Interface";
		writer.printText(key, classlink);
		writer.boldEnd();
	}
	
	protected void printSummaryType(ProgramElementDoc member) {
		MethodDoc meth = (MethodDoc) member;
		printModifierAndType(meth, meth.returnType());
	}
	
	protected static void printOverridden(HtmlDocletWriter writer,
			Type overriddenType, MethodDoc method) {
		if (writer.configuration.nocomment) {
			return;
		}
		ClassDoc holderClassDoc = overriddenType.asClassDoc();
		if (!(holderClassDoc.isPublic() || Util.isLinkable(holderClassDoc,
				writer.configuration()))) {
			// This is an implementation detail that should not be documented.
			return;
		}
		if (overriddenType.asClassDoc().isIncluded() && !method.isIncluded()) {
			// The class is included but the method is not. That means that it
			// is not visible so don't document this.
			return;
		}
		String label = "doclet.Overrides";
		int context = LinkInfoImpl.CONTEXT_METHOD_OVERRIDES;
		
		if (method != null) {
			if (overriddenType.asClassDoc().isAbstract() && method.isAbstract()) {
				// Abstract method is implemented from abstract class,
				// not overridden
				label = "doclet.Specified_By";
				context = LinkInfoImpl.CONTEXT_METHOD_SPECIFIED_BY;
			}
			String overriddenTypeLink = writer.codeText(writer.getLink(new LinkInfoImpl(
					context, overriddenType)));
			String name = method.name();
			writer.dt();
			writer.boldText(label);
			writer.dd();
			String methLink = writer.codeText(writer.getLink(new LinkInfoImpl(
					LinkInfoImpl.CONTEXT_MEMBER, overriddenType.asClassDoc(),
					writer.getAnchor(method), name, false)));
			writer.printText("doclet.in_class", methLink, overriddenTypeLink);
		}
	}
	
	/**
	 * Parse the &lt;Code&gt; tag and return the text.
	 */
	protected String parseCodeTag(String tag) {
		if (tag == null) {
			return "";
		}
		
		String lc = tag.toLowerCase();
		int begin = lc.indexOf("<code>");
		int end = lc.indexOf("</code>");
		if (begin == -1 || end == -1 || end <= begin) {
			return tag;
		} else {
			return tag.substring(begin + 6, end);
		}
	}
	
	protected static void printImplementsInfo(HtmlDocletWriter writer,
			MethodDoc method) {
		if (writer.configuration.nocomment) {
			return;
		}
		ImplementedMethods implementedMethodsFinder = new ImplementedMethods(
				method, writer.configuration);
		MethodDoc[] implementedMethods = implementedMethodsFinder.build();
		for (int i = 0; i < implementedMethods.length; i++) {
			MethodDoc implementedMeth = implementedMethods[i];
			Type intfac = implementedMethodsFinder.getMethodHolder(implementedMeth);
			String methlink = "";
			String intfaclink = writer.codeText(writer.getLink(new LinkInfoImpl(
					LinkInfoImpl.CONTEXT_METHOD_SPECIFIED_BY, intfac)));
			writer.dt();
			writer.boldText("doclet.Specified_By");
			writer.dd();
			methlink = writer.codeText(writer.getDocLink(
					LinkInfoImpl.CONTEXT_MEMBER, implementedMeth,
					implementedMeth.name(), false));
			writer.printText("doclet.in_interface", methlink, intfaclink);
		}
		
	}
	
	protected void printReturnType(MethodDoc method) {
		Type type = method.returnType();
		if (type != null) {
			writer.printLink(new LinkInfoImpl(LinkInfoImpl.CONTEXT_RETURN_TYPE,
					type));
			print(' ');
		}
	}
	
	protected void printNavSummaryLink(ClassDoc cd, boolean link) {
		if (link) {
			writer.printHyperLink("", (cd == null)
					? "method_summary"
					: "methods_inherited_from_class_"
							+ Config.getInstance().getClassName(cd),
					Config.getInstance().getText("doclet.navMethod"));
		} else {
			writer.printText("doclet.navMethod");
		}
	}
	
	protected void printNavDetailLink(boolean link) {
		if (link) {
			writer.printHyperLink("", "method_detail",
					Config.getInstance().getText("doclet.navMethod"));
		} else {
			writer.printText("doclet.navMethod");
		}
	}
}
